<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------

namespace buwang\traits;

use app\manage\model\Token;
use buwang\exception\MiniappException;
use think\facade\Config;
use think\facade\View;
use buwang\service\AuthService;
use buwang\exception\AuthException;
use think\Session;

/**
 * 插件Trait
 * @author: JiaoYuKun
 * @day: 2019/12/9
 */
trait PluginTrait
{
    /**
     * 无需登录的方法,同时也就不需要鉴权了
     * @var array
     */
    protected $noNeedLogin = [];

    /**
     * 无需鉴权的方法,但需要登录
     * @var array
     */
    protected $noNeedRight = [];
    /**
     * 权限控制类
     * @var AuthService
     */
    protected $auth_service = null;
    // 当前插件操作
    protected $addon = '';
    //插件路径
    protected $controller = null;
    protected $action = null;
    // 插件路径
    protected $addon_path;
    // 视图模型
    protected $view;
    // 插件配置
    private $addon_config;
    // 插件信息
    private $addon_info;
    //布局模板
    protected $layout = '../../../view/public/layout';

    //插件必备构造
    protected function pluginConstruct(\think\App $app)
    {//移除HTML标签
        $app->request->filter('trim,strip_tags,htmlspecialchars');
        // 是否自动转换控制器和操作名
        $convert = Config::get('url_convert');
        $filter = $convert ? 'strtolower' : 'trim';
        // 处理路由参数
        $var = $app->request->rule()->getVars();
        $addon = isset($var['addon']) ? $var['addon'] : '';
        $controller = isset($var['controller']) ? $var['controller'] : '';
        $action = isset($var['action']) ? $var['action'] : '';

        //当前插件名，方法，控制器
        $this->addon = $addon ? call_user_func($filter, $addon) : '';
        $this->controller = $controller ? call_user_func($filter, $controller) : 'index';
        $this->action = $action ? call_user_func($filter, $action) : 'index';

        $this->addon_path = $app->addons->getAddonsPath() . $this->addon . DIRECTORY_SEPARATOR;
        $this->addon_config = "addon_{$this->addon}_config";
        $this->addon_info = "addon_{$this->addon}_info";

        //view模板，layout模板布局设置
        $this->view = clone VIEW::engine('Think');
        $view_data = Config::get('view');
        $view_data['tpl_replace_string']['__ADDON__'] = '/static/addons/' . $this->addon . '/';
        $this->view->config($view_data);
        // 如果有使用模板布局
        $this->layout && $app->view->engine()->layout($this->layout);
        //Config::set(,'view')

        /*--------------------------------copy from \buwang\middleware\ViewInit.php Start------------------------------*/
        $request = request();
        $token = get_token($request);
        $user_id = 0;
        if ($token) {//登录过
            try {
                $jwtinfo = self::decodeToken($token);//解析token,获取用户信息
                $user = Token::validateRedisToken($token, $jwtinfo);
                $user && ($user_id = $user->id) && ($this->uid = $user->id) && ($this->user = $user);
            } catch (\Throwable $e) {
                $user_id = 0;
            }
        }
       
        $thisModule = "addons/{$this->addon}";
        $thisController = $this->controller;
        $thisAction = $this->action;
        list($thisControllerArr, $jsPath) = [explode('.', $thisController), null];
        //var_dump($thisControllerArr);die;
        foreach ($thisControllerArr as $vo) {
            empty($jsPath) ? $jsPath = parse_name($vo) : $jsPath .= '/' . parse_name($vo);
        }
        $autoloadJs = file_exists(root_path('public') . "static/{$thisModule}/js/{$jsPath}.js") ? true : false;
        $thisControllerJsPath = "{$thisModule}/js/{$jsPath}.js";
        //$adminModuleName = config('app.admin_alias_name');
        $adminModuleName = $thisModule;
        $isSuperAdmin = $user_id == config('auth.super_admin_id');
        $data = [
            'adminModuleName' => $adminModuleName,
            'thisController' => parse_name($thisController),
            'thisAction' => $thisAction,
            'thisRequest' => parse_name("{$thisModule}/{$thisController}/{$thisAction}"),
            'thisControllerJsPath' => "{$thisControllerJsPath}",
            'autoloadJs' => $autoloadJs,
            'isSuperAdmin' => $isSuperAdmin,
            'domain' => $request->domain(),
            'version' => env('app_debug') ? time() : '1.0.0',
        ];
        $this->assign($data);
        /*--------------------------------copy from \buwang\middleware\ViewInit.php End------------------------------*/
    }

    //插件必备初始化函数 插件权限节点鉴权
    protected function pluginInitialize()
    {
        //转化获取当前的路由节点地址
        $node = "/addons/{$this->addon}/" . parse_name("{$this->controller}", 1) . "/{$this->action}";
        $this->auth_service = AuthService::instance();
        //传入当前请求的方法
        $this->auth_service->setAction($this->action);
        // 检测是否需要验证登录
        if (!$this->auth_service->match($this->noNeedLogin)) {
            //检测是否登录
            $member_id_info = \buwang\util\Util::getLoginMemberId();//得到登录信息
            $jwtinfo = $member_id_info['jwtinfo'];
            if (!$jwtinfo) throw new AuthException('请去登录',401);
            // 判断是否需要验证权限
            if (!$this->auth_service->match($this->noNeedRight)) {
                // 判断控制器和方法判断是否有对应权限
                $uid = $jwtinfo->data->id;
                AuthService::auth($uid, $member_id_info['scopes'], $node);
            }
        }
    }

    /**
     * 加载模板输出
     * @param string $template
     * @param array $vars 模板文件名
     * @return false|mixed|string   模板输出变量
     * @throws \think\Exception
     */
    protected function fetch($template = '', $vars = [])
    {
        return $this->view->fetch($template, $vars);
    }

    /**
     * 渲染内容输出
     * @access protected
     * @param string $content 模板内容
     * @param array $vars 模板输出变量
     * @return mixed
     */
    protected function display($content = '', $vars = [])
    {
        return $this->view->display($content, $vars);
    }

    /**
     * 模板变量赋值
     * @access protected
     * @param mixed $name 要显示的模板变量
     * @param mixed $value 变量的值
     * @return $this
     */
    protected function assign($name, $value = '')
    {
        if (is_array($name)) {
            $this->view->assign($name);
        } else {
            $this->view->assign([$name => $value]);
        }

        return $this;
    }

    /**
     * 初始化模板引擎
     * @access protected
     * @param array|string $engine 引擎参数
     * @return $this
     */
    protected function engine($engine)
    {
        $this->view->engine($engine);

        return $this;
    }

    /**
     * 插件基础信息
     * @return array
     */
    final public function getInfo()
    {
        $info = Config::get($this->addon_info, []);
        if ($info) {
            return $info;
        }

        // 文件属性
        $info = $this->info ?? [];
        // 文件配置
        $info_file = $this->addon_path . 'info.ini';
        if (is_file($info_file)) {
            $_info = parse_ini_file($info_file, true, INI_SCANNER_TYPED) ?: [];
            $_info['url'] = addons_url();
            $info = array_merge($_info, $info);
        }
        Config::set($info, $this->addon_info);

        return isset($info) ? $info : [];
    }

    /**
     * 获取配置信息
     * @param bool $type 是否获取完整配置
     * @return array|mixed
     */
    final public function getConfig($type = false)
    {
        $config = Config::get($this->addon_config, []);
        if ($config) {
            return $config;
        }
        $config_file = $this->addon_path . 'config.php';
        if (is_file($config_file)) {
            $temp_arr = (array)include $config_file;
            if ($type) {
                return $temp_arr;
            }
            foreach ($temp_arr as $key => $value) {
                $config[$key] = $value['value'];
            }
            unset($temp_arr);
        }
        Config::set($config, $this->addon_config);

        return $config;
    }
}
